import pygame, tile, mob, mobmanager, spritemanager, constants, random, UIManager
from pygame.locals import *

from tile import *
from mob import *
from mobmanager import *
from spritemanager import *
from constants import *
from UIManager import *
#Image loading: from spritesheets, loadImage. From regular image files, legacyLoadImage
#Creation of image dictionary: createImageDictionary
#Map generation: generateSelf
#mob updating: inherit from MobManager, change functionality, set map's mobManager to your custom one (updateMobs)
#movement handling: checkMove, called in your custom mob manager or the generic one
#drawing: render
#map saving: exportSelf and the ExportMap class


class Encounter:
    """Manages combat between two mobs"""
    def __init__(self, attacker, defender, scene):
        """Initialize an encounter with the specified parameters"""
        print "Initiating encounter between %s and %s!" % (attacker.name, defender.name)
        self.scene = scene
        self.active = False
        self.winner = None
        self.loser = None
        self.attacker = attacker
        self.defender = defender
        if self.attacker.name == "Markowsky":
            self.status1 = "You confront %s!" % (attacker.name)
            self.status2 = "Prepare for the fight of your academic life!"
        else:
            self.status1 = "You confront %s!" % (attacker.name)
            self.status2 = "Your grades are in mortal danger!"
        self.attackerMove = None
        self.defenderMove = None
        self.choiceList = None

    def createChoiceList(self, surface):
        """Creates a ChoiceList containing the list of actions the player can take in combat"""
        #make the list of move choices for the player
        choices = []
        for move in self.defender.moves:
            choices.append(move.name)

        font = pygame.font.SysFont("Courier New", 20)

        self.choiceList = ChoiceList(surface, (TILESIZE * MAP_WIDTH) / 2, 650, choices, font, font)
        self.choiceList.x = (self.scene.surface.get_width() / 2) - (self.choiceList.width / 2) + 30
        self.choiceList.y = 580
        self.choiceList.drawSelf()

    def selectAttackerMove(self, move):
        """Selects the attacker's move.

        move: the move that the attacker will make"""
        self.attackerMove = move

    def selectDefenderMove(self):
        """Figures out which move the player has selected and sets that as this turn's move."""
        selectedMoveName = self.choiceList.getSelectedChoice()

        for move in self.defender.moves:
            if move.name == selectedMoveName:
                self.defenderMove = move
                self.status1 = "You choose %s!" % selectedMoveName

    def determineMove(self, mob):
        """Picks a random move from the list of moves the mob is eligible for and returns it.

        mob: the mob that the move will be picked for"""
        if len(mob.moves == 0):
            print "Mob has no moves!"
            return None
        else:
            return random.choice(mob.moves)

    def makeMove(self):
        """Calculates and displays the results of one round of combat"""
        if not self.active:
            return

        if self.attacker.energy <= 0:
            self.winner = self.defender
            self.loser = self.attacker
            self.winner.points += (20 + (5 * self.loser.power))
            self.status1 = "You win! Your score has increased by %d!" % (20 + (5 * self.loser.power))
            self.status2 = "The battle brought your GPA to %0.2f." % (self.defender.gpa)
            self.scene.refreshGUI()
            self.active = False
            return

        if self.defender.energy <= 0:
            self.winner = self.attacker
            self.loser = self.defender
            self.status1 = "You lose!"

            if self.loser.points <= 0:
                self.status2 = "You weren't doing well enough to lose any points! Your GPA and energy have been reset."
            else:
                self.status2 = "Your score has been decreased and your GPA and energy reset."
                self.loser.points -= 10
                
            self.loser.gpa = 4.0
            self.loser.energy = 10
            self.scene.refreshGUI()
            self.active = False
            return

        if self.attackerMove is not None:
            #reduce the player's GPA by the move's power, then lower the TA's energy
            #randomize the attack's power a little bit
            powerMod = random.choice([-0.1, 0.1])
            self.status1 = "%s used %s, hurting your GPA by %0.2f points!" % (self.attacker.name, self.attackerMove.name, self.attackerMove.power + powerMod)
            self.defender.gpa -= (self.attackerMove.power + powerMod)
            if self.defender.gpa < 0.0:
                self.defender.gpa = 0.0
            self.attacker.energy -= 2 #5 moves/TA
            self.scene.refreshGUI()

        if self.defenderMove is not None:
            #randomize the defense power a little bit
            powerMod = random.choice([-0.1, 0.1])
            self.status2 = "You used %s, healing your GPA by %0.2f points!" % (self.defenderMove.name, self.defenderMove.power + powerMod)
            #increase the player's GPA by the move's power, then lower the player's energy
            #make sure that we can only have 4.0 GPA maximumg
            self.defender.gpa = min(self.defender.gpa + self.defenderMove.power + powerMod, 4.0)
            self.defender.energy -= 1 #10 moves/player
            self.scene.refreshGUI()

class Scene:
    """Manages UI, active maps, game state, and... well, basically everything. Contender for the "most bloated class" award"""
    def __init__(self, surface):
        """Initializes a scene with the given surface"""
        self.mapSurface = pygame.surface.Surface(((TILESIZE * MAP_WIDTH) * 2, (TILESIZE * MAP_HEIGHT) *2))
        self.width = ((TILESIZE * MAP_WIDTH) * 2 + 100)
        self.height = 700
        self.mapSurfaceOffset = ((TILESIZE * MAP_WIDTH) * 2)
        self.hasWon = False
        self.surface = surface
        self.activeEncounter = None
        self.beginCallbacks = []
        self.endCallbacks = []
        self.maps = []
        self.mobManagers = []
        self.inputManager = InputManager()
        self.activeMap = None
        self.mapRect = None
        self.status1 = "Your goal: defeat Markowsky!"
        self.status2 = "Defeat the TAs until you can battle him!"
        self.playerHasWon = False

        font = pygame.font.SysFont("Courier New", 12)
        self.statusLabel1 = Label(self.surface, 0, self.mapSurfaceOffset + 42, font, self.status1)
        self.statusLabel1.x = (self.width / 2) - (self.statusLabel1.width / 2)
        self.statusLabel2 = Label(self.surface, 0, self.statusLabel1.y + 21, font, self.status2)
        self.statusLabel2.x = (self.width / 2) - (self.statusLabel2.width / 2)
        self.statusLabel3 = Label(self.surface, 0, self.height, font, " ")
        self.statusLabel1.updateContent(None)
        self.statusLabel2.updateContent(None)
        print "SceneManager initialized successfully"

    def begin(self):
        """Informs all objects that have subscribed to this scene's begin notification that the scene has begun"""
        for method in self.beginCallbacks:
            method()

    def end(self):
        """Informs all objects that have subscribed to this scene's end notification that the scene has ended"""
        for method in self.endCallbacks:
            method()

    def addMap(self, tileMap):
        """Activates the given map. If a map is currently active, it deactivates it. Adds the map to it's list of maps"""
        if self.activeMap == tileMap:
            self.deactivateMap(tileMap)
        self.maps.append(tileMap)

    def removeMap(self, map):
        """Removes a map from the scene's list of maps"""
        self.maps.remove(map)

    def makeMapActive(self, tileMap):
        """Activates a given map, hooking the UI to it and letting it handle input for the player's movement."""
        if not tileMap in self.maps:
            self.maps.append(tileMap)
        self.activeMap = tileMap
        self.inputManager.registerHandler(tileMap.handlePlayerMovement)
        self.mapRect = pygame.rect.Rect(0, 0, TILESIZE * MAP_WIDTH, TILESIZE * MAP_HEIGHT)

        font = pygame.font.SysFont("Courier New", 12)
        fontmid = pygame.font.SysFont("Courier New", 14)
        self.playerGPALabel = Label(self.surface, 50, self.mapSurfaceOffset, fontmid, "Your GPA: " + str(self.activeMap.player.gpa))
        self.playerEnergyLabel = Label(self.surface, self.width / 2, self.mapSurfaceOffset, fontmid, "Your Energy: " + str(self.activeMap.player.energy))
        self.playerEnergyLabel.x = (self.width / 2) - (self.playerEnergyLabel.width / 2)
        self.playerPointsLabel = Label(self.surface, self.width, self.mapSurfaceOffset, fontmid, "Your Points: " + str(self.activeMap.player.points))
        self.playerPointsLabel.x = (self.width - self.playerPointsLabel.width) - 50
        self.statusLabel3 = Label(self.surface, 0, self.height, fontmid, self.activeMap.status)
        self.statusLabel3.x = (self.width / 2) - (self.statusLabel3.width / 2)
        self.statusLabel3.y = self.height - self.statusLabel3.height
        self.playerGPALabel.updateContent(None)
        self.playerEnergyLabel.updateContent(None)
        self.playerPointsLabel.updateContent(None)
        self.statusLabel3.updateContent(None)

        self.playerGPALabel.drawSelf()
        self.playerEnergyLabel.drawSelf()
        self.playerPointsLabel.drawSelf()
        self.statusLabel3.drawSelf()
        print "SceneManager activated map"

    def deactivateMap(self, tileMap):
        """Unhooks keyboard input from the given and deactivates it"""
        self.inputManager.unregisterHandler(tileMap.handlePlayerMovement)
        self.activeMap = None
        self.mapRect = None
        self.surface.fill((0, 0, 0))
        print "SceneManager deactivated map"

    def makeEncounterActive(self, encounter):
        """Allows an Encounter to handle keyboard input instead of the active map. Checks to make sure the player is able to fight Markowsky (that enough TAs have been defeated) before letting him do so."""
        if encounter.attacker.name == "Markowsky" and self.activeMap.defeatedTAs != self.activeMap.totalTAs - 1:
            self.status1 = "You can't fight Markowsky yet!"
            self.status2 = "Defeat his TAs first!"
            return

        self.surface.fill((0, 0, 0))
        encounter.active = True
        self.activeEncounter = encounter
        print "SceneManager activated encounter"
        #remove the inputmanager's old input handler and save it for later
        self.oldHandler = self.inputManager.handlers[0]
        self.inputManager.unregisterHandler(self.oldHandler)
        self.inputManager.registerHandler(self.handleEncounterInput)
        self.activeEncounter.createChoiceList(self.surface)

        #create the UI
        font = pygame.font.SysFont("Courier New", 12)
        self.TAEnergyLabel = Label(self.surface, self.playerEnergyLabel.x, self.playerEnergyLabel.y + 21, font, "TA's Energy: " + str(encounter.attacker.energy))

        self.playerGPALabel.updateContent("Your GPA: " + str(self.activeMap.player.gpa))
        self.playerEnergyLabel.updateContent("Your Energy: " + str(self.activeMap.player.energy))
        self.TAEnergyLabel.updateContent(None)
        self.statusLabel1.updateContent(self.activeEncounter.status1)
        self.statusLabel2.updateContent(self.activeEncounter.status2)
        self.statusLabel3.updateContent(self.activeMap.status)

        self.recenterLabel(self.statusLabel1)
        self.recenterLabel(self.statusLabel2)
        self.recenterLabel(self.statusLabel3)

    def handleEncounterInput(self, event):
        """Determines whether the input is valid for this encounter and updates it if it is. Returns whether the input was valid"""
        #also updates the encounter!
        if self.activeEncounter is None:
            print "SceneManager tried to handle encounter input with no active encounter!"
            return

        if self.activeEncounter.choiceList is not None:
            if event.key == K_UP:
                self.activeEncounter.choiceList.selectPreviousItem()
            if event.key == K_DOWN:
                self.activeEncounter.choiceList.selectNextItem()
            if event.key == K_RETURN:
                self.activeEncounter.selectAttackerMove(random.choice(self.activeEncounter.attacker.moves))
                self.activeEncounter.selectDefenderMove()
                self.activeEncounter.makeMove()

            return True

    def refreshGUI(self):
        """Fills the screen with black and redraws all GUI elements. Quietly fails if a UI element does not yet exist, but draws elements up to that one"""
        try:
            self.surface.fill((0, 0, 0))
            self.recenterLabel(self.statusLabel1)
            self.recenterLabel(self.statusLabel2)
            self.recenterLabel(self.statusLabel3)

            self.statusLabel1.drawSelf()
            self.statusLabel2.drawSelf()
            self.statusLabel3.drawSelf()

            self.playerGPALabel.drawSelf()
            self.playerEnergyLabel.drawSelf()
            self.playerPointsLabel.drawSelf()

            if self.activeEncounter is not None:
                #self.activeEncounter.choiceList.x = ((self.surface.get_width() / 2) - (self.activeEncounter.choiceList.width / 2))
                self.TAEnergyLabel.drawSelf()
                self.activeEncounter.choiceList.drawSelf()
            self.renderScene()

        except Exception:
            #pokemon exception handling
            pass

    def recenterLabel(self, label):
        """Helper method that centers a given label in the x axis. Accounts for the text content of the label"""
        self.surface.blit(label.calculateClearSurface(), (label.x, label.y))
        label.x = (self.width / 2) - (label.width / 2)

    def drawStatusLabels(self):
        """Recenters and redraws status labels. Called from maps when those and only those labels specifically need to be updated."""
        if self.statusLabel1 is not None:
            self.recenterLabel(self.statusLabel1)
            self.statusLabel1.drawSelf()
        if self.statusLabel2 is not None:
            self.recenterLabel(self.statusLabel2)
            self.statusLabel2.drawSelf()
        if self.statusLabel3 is not None:
            self.recenterLabel(self.statusLabel3)
            self.statusLabel3.drawSelf()

    def updateMapStatus(self):
        """Updates the Scene's status3 (the content of the third status label) to match whatever the active map currently wants it to be"""
        if self.activeMap is not None:
            self.statusLabel3.updateContent(self.activeMap.status)
            self.recenterLabel(self.statusLabel3)

    def deactivateEncounter(self, encounter):
        """Deactivates the specified encounter and returns keyboard input to whatever had it before the encounter did. Checks to see if the player has won (if he's defeated all enemies)."""
        print "SceneManager deactivating encounter..."
        #first: "destroy" the TA if the TA was the loser
        if encounter.loser == encounter.attacker:
            if encounter.attacker in self.activeMap.mobManager.mobs:
                self.activeMap.mobs.remove(encounter.attacker)
            self.activeMap.defeatedTAs += 1
            if self.activeMap.defeatedTAs == 4:
                self.hasWon = True

        encounter.active = False
        self.activeEncounter = None
        self.inputManager.unregisterHandler(self.handleEncounterInput)
        self.inputManager.registerHandler(self.oldHandler)
        #fill the surface with black in order to reset GUI elements
        self.surface.fill((0, 0, 0))
        self.updateScene(None)
        print "SceneManager deactivated encounter"

    def updateScene(self, event):
        """The most important method in the Scene class. Updates UI elements, determines whether maps need to change or encounters have occurred, and updates the game's status accordingly."""
        #update the GUI elements that are always on the screen
        self.statusLabel1.updateContent(self.status1)
        self.recenterLabel(self.statusLabel1)
        self.statusLabel2.updateContent(self.status2)
        self.recenterLabel(self.statusLabel2)

        if self.activeMap is not None:
            self.statusLabel3.updateContent(self.activeMap.status)
        else:
            self.surface.blit(self.statusLabel3.calculateClearSurface())

        self.playerGPALabel.updateContent("Your GPA: " + str(self.activeMap.player.gpa))
        self.playerEnergyLabel.updateContent("Your Energy: " + str(self.activeMap.player.energy))
        values = self.inputManager.handleInput(event)

        #check to see if we've started an encounter
        if self.activeMap.mobManager.activeEncounter is not None and self.activeEncounter is None:
            toActivate = self.activeMap.mobManager.activeEncounter
            self.activeMap.mobManager.activeEncounter = None
            self.makeEncounterActive(toActivate)

        #update the labels we use to draw encounter stuff, if necessary
        if self.activeEncounter is not None:
            encounter = self.activeEncounter
            self.playerGPALabel.updateContent("Your GPA: " + str(encounter.defender.gpa))
            self.playerEnergyLabel.updateContent("Your Energy: " + str(encounter.defender.energy))
            self.TAEnergyLabel.updateContent("TA's Energy: " + str(encounter.attacker.energy))
            self.statusLabel1.updateContent(self.activeEncounter.status1)
            self.statusLabel2.updateContent(self.activeEncounter.status2)

        #check to see if the encounter is over
        if self.activeEncounter is not None and self.activeEncounter.active == False:
            self.status1 = self.activeEncounter.status1
            self.status2 = self.activeEncounter.status2
            self.deactivateEncounter(self.activeEncounter)

        if self.activeEncounter is None:
            self.playerPointsLabel.updateContent("Your Points: " + str(self.activeMap.player.points))

        self.refreshGUI()
        return values

    def renderScene(self):
        """Call this to force the scene to render its active map to its active surface RIGHT NOW"""
        if self.activeMap is not None:
            pygame.transform.scale(self.activeMap.render(), ((TILESIZE * MAP_WIDTH) * 2, (TILESIZE * MAP_HEIGHT) * 2), self.mapSurface)
            width = self.mapSurface.get_width()
            self.surface.blit(self.mapSurface, ((self.width / 2) - (width / 2), 0))

class InputManager:
    """Handles and directs keyboard input to appropriate game components"""
    def __init__(self):
        """Initializes the InputManager"""
        self.handlers = []

    def registerHandler(self, handler):
        """Registers a given method as one that will be used to handle keyboard input"""
        print "InputManager registered handler number %d: %s" % (len(self.handlers), handler.__name__)
        self.handlers.append(handler)

    def unregisterHandler(self, handler):
        """Unregisters a given handler that has been previously registered (keeps it from receiving keyboard input)"""
        print "InputManager unregistered a handler"
        self.handlers.remove(handler)

    def handleInput(self, event):
        """Passes the keyboard event to the handlers currently subscribed"""
        if event is None:
            return False
        #normally we'd go through all of these, but right now we'll only ever handle one
        #for handler in self.handlers:
        #    yield handler(event)
        return self.handlers[0](event)

class Map:
    """Manages and generates the actual map on screen"""
    def __init__(self, scene):
        """Creates a map belonging to the specified scene"""
        self.renderSurface = pygame.Surface((TILESIZE * MAP_WIDTH, TILESIZE*MAP_HEIGHT))
        self.scene = scene
        self.hasInsideMap = False
        self.hasOutsideMap = False
        self.totalTAs = 4
        self.defeatedTAs = 0
        self.playerEntryPoint = [5, 5]
        self.layers = []
        self.mobs = []
        self.images = {}
        self.legacyImages = []
        self.groundPath = "environment.png"
        self.groundSpriteManager = SpriteManager(self.groundPath, (TILESIZE, TILESIZE), 8)

        self.surface = None
        self.hasDeterminedSurface = False
        self.outsideMap = None
        self.insideMap = None
        self.isInside = True
        self.status = None
        self.oldStatus = self.status
        self.createImageDictionary()
        self.generateInsideMap()
        self.player = Mob(self.legacyImages[0], [self.playerEntryPoint[0] * TILESIZE, self.playerEntryPoint[1] * TILESIZE], name="Player")
        
        #make the player's moves
        study = Move("Study", 0.4)
        homework = Move("Do Homework", 0.2)
        confuse = Move("Ask Confusing Question", 0.3)
        self.player.moves = [study, homework, confuse]

        #make the TA's moves
        test = Move("Fail Player On Test", 0.5)
        quiz = Move("Fail Player On Quiz", 0.2)
        lab = Move("Fail Player On Lab", 0.2)
        manip = Move("Manipulate Player's Grade", 0.5)

        #markowsky's moves!
        perl = Move("Incomprehensible Perl Script", 0.8)
        np = Move("NP-Hard Homework Problem", 1.0)
        edit = Move("Edit Player's Test Scores", 0.8)
        time = Move("Lecture Past End Of Class", 0.7)
        accel = Move("Accelerate Curriculum", 0.6)

        moves = [test, quiz, lab, manip]
        markowskymoves = [perl, np, edit, time, accel]
        
        self.mobs.append(Mob(self.legacyImages[1], [16 * 6, 16 * 6], isAI=True, name="Evil TA", moves=moves))
        self.mobs.append(Mob(self.legacyImages[1], [16 * 6, 16 * 7], isAI=True, name="Malicious TA", moves=moves))
        self.mobs.append(Mob(self.legacyImages[1], [16 * 6, 16 * 8], isAI=True, name="Evil TA 2", moves=moves))
        self.mobs.append(Mob(self.legacyImages[3], [16 * 6, 16 * 9], isAI=True, name="Markowsky", moves=markowskymoves))

        self.mobManager = MobManager(self.mobs, self.player, self)

    def loadImage(self, ID, scale=True, useColorkey=None, colorkeyColor=(255, 255, 255)):
        """Loads an image from the map's SpriteManager's spritesheet"""
        try:
            image = self.groundSpriteManager.imageFromID(ID, colorkey=useColorkey, colorkeyColor=colorkeyColor)
            if scale:
                image = pygame.transform.scale(image, (16, 16))
            if useColorkey is not None:
                image.set_colorkey(colorkeyColor, RLEACCEL)
            self.images[ID] = image
            print "Map loaded image id %d" % (ID)
        except Exception, message:
            print "Map failed to load image id %d" % (ID)
            raise Exception, message

    def createImageDictionary(self):
        """Loads all images in a 16x16 spritesheet into memory and assigns them IDs in a dictionary"""
        #expects a sheet of 16x16 images
        for x in range(16 * 16):
            self.images[x] = pygame.transform.scale(self.groundSpriteManager.imageFromID(x), (16, 16))
    
    def generateInsideMap(self):
        """Transitions the map to an inside state. Hacky; this class was not intended to be used this way"""
        self.status = "You stand in the dungeon of Neville Hall..."
        self.oldStatus = self.status
        self.isInside = True

        if (self.hasInsideMap):
            self.layers = self.insideMap
        else:
            self.layers = []
            self.hasInsideMap = True
            self.legacyImages.append(self.groundSpriteManager.imageFromPath("player.png", useColorkey=True))
            self.legacyImages.append(self.groundSpriteManager.imageFromPath("pirate.png", useColorkey=True))
            self.legacyImages.append(self.groundSpriteManager.imageFromPath("bed.png", useColorkey=True))
            self.legacyImages.append(self.groundSpriteManager.imageFromPath("markowsky.png", useColorkey=True))

            layer = []

            #can do this with list comprehensions but it's harder to maintain
            for x in range(MAP_WIDTH):
                currentRow = []
                for y in range(MAP_HEIGHT):
                    #make the tiles walls if they're on the edge of the map
                    #the reason they're declared outside of the call to append is because it makes adding them to the list of all tiles easier
                    if x == 0 or x == MAP_WIDTH - 1:
                        if y % 5 == 0 or y == MAP_HEIGHT - 1: #add a torch every few spaces
                            addTile = Tile(self.images[1], True, x * TILESIZE, y * TILESIZE)
                        else:
                            addTile = Tile(self.images[5], True, x * TILESIZE, y * TILESIZE)
                        currentRow.append(addTile)
                        continue

                    if y == 0 or y == MAP_HEIGHT - 1:
                        if not x % 5: #add a torch every few spaces
                            addTile = Tile(self.images[1], True, x * TILESIZE, y * TILESIZE)
                        else:
                            addTile = Tile(self.images[5], True, x * TILESIZE, y * TILESIZE)
                        currentRow.append(addTile)
                        continue
                    #if random.randint(1, 30) == 1:
                    #    addTile = Tile(self.images[8], False, x * TILESIZE, y * TILESIZE)
                    #else:
                    addTile = Tile(self.images[6], False, x * TILESIZE, y * TILESIZE)
                    currentRow.append(addTile)
                layer.append(currentRow)

            self.layers.append(layer)

            objectLayer = []
            #objectLayer.append([Tile(self.legacyImages[2], False, 1 * TILESIZE, 1 * TILESIZE, action=SleepAction())])

            for x in range(MAP_WIDTH):
                currentRow = []
                for y in range(MAP_HEIGHT):
                    if x == 1 and y == 1:
                        toAppend = Tile(self.images[7], False, x * TILESIZE, y * TILESIZE, action=GoOutsideAction())
                        currentRow.append(toAppend)
                objectLayer.append(currentRow)

            self.layers.append(objectLayer)
            self.insideMap = self.layers

        self.scene.updateMapStatus()
        self.scene.drawStatusLabels()

    def generateOutsideMap(self):
        """Transitions the map to an outside state. Hacky; this class was not intended to be used this way"""
        self.status = "You see the unusually barren UMaine campus."
        self.oldStatus = self.status
        self.isInside = False
        if self.hasOutsideMap:
            self.layers = self.outsideMap
        else:
            self.layers = []
            self.hasOutsideMap = True

            layer = []
            for x in range(MAP_WIDTH):
                currentRow = []
                for y in range(MAP_HEIGHT):
                    #make the tiles walls if they're on the edge of the map
                    #the reason they're declared outside of the call to append is because it makes adding them to the list of all tiles easier
                    if x == 0 or x == MAP_WIDTH - 1:
                        addTile = Tile(self.images[71], True, x * TILESIZE, y * TILESIZE)
                        currentRow.append(addTile)
                        continue

                    if y == 0 or y == MAP_HEIGHT - 1:
                        addTile = Tile(self.images[71], True, x * TILESIZE, y * TILESIZE)
                        currentRow.append(addTile)
                        continue

                    addTile = Tile(self.images[71], False, x * TILESIZE, y * TILESIZE)
                    currentRow.append(addTile)
                layer.append(currentRow)

            self.layers.append(layer)

            objectLayer = []
            #objectLayer.append([Tile(self.legacyImages[2], False, 1 * TILESIZE, 1 * TILESIZE, action=SleepAction())])

            for x in range(MAP_WIDTH):
                currentRow = []
                for y in range(MAP_HEIGHT):
                    if x == 1 and y == 1:
                        toAppend = Tile(self.images[8], False, x * TILESIZE, y * TILESIZE, action=GoInsideAction())
                        currentRow.append(toAppend)
                    if x == 2 and y == 1:
                        toAppend = Tile(self.images[135], False, x * TILESIZE, y * TILESIZE, action=SleepAction())
                        currentRow.append(toAppend)
                objectLayer.append(currentRow)

            self.layers.append(objectLayer)
            self.outsideMap = self.layers
            
        self.scene.updateMapStatus()
        self.scene.drawStatusLabels()

    def updateMobs(self):
        """Updates the mobs that this map's MobManager knows about"""
        self.mobManager.updateMobs()

    def checkMove(self, mob):
        """Uses this map's MobManager to determine if a mob is capable of making a move (if the tile isn't solid, etc)"""
        self.mobManager.checkMove(mob)
           
    def handlePlayerMovement(self, event):
        """Checks to see if the player has performed an action or moved. Handles each accordingly"""
        if self.status != self.oldStatus:
            self.status = self.oldStatus
        if not event.type == KEYUP:
            return

        if event.key == K_LEFT:
            self.mobManager.player.move(-1, 0)
            self.updateMobs()
            return True
        elif event.key == K_RIGHT:
            self.mobManager.player.move(1, 0)
            self.updateMobs()
            return True
        elif event.key == K_UP:
            self.mobManager.player.move(0, -1)
            self.updateMobs()
            return True
        elif event.key == K_DOWN:
            self.mobManager.player.move(0, 1)
            self.updateMobs()
            return True
        elif event.key == K_RETURN:
            #see what tile the player is on
            playerCoords = self.player.getTileCoords()
            #for layer in self.layers:
            for row in self.layers[0]:
                for tile in row:
                    if tile.getTileCoords() == playerCoords:
                        result = tile.action.doAction(self.player, self)
                        if not result:
                            break
                        else:
                            self.scene.updateMapStatus()
                            self.scene.drawStatusLabels()
                            return result

            for x in range(0, len(self.layers)):
                if not x:
                    continue
                for row in self.layers[x]:
                    for tile in row:
                        if tile.getTileCoords() == playerCoords:
                            result = tile.action.doAction(self.player, self)
                            if result:
                                self.scene.updateMapStatus()
                                self.scene.drawStatusLabels()
                                return result

    def render(self):
        """Draws the map (and, depending, its mobs) to a surface and returns it."""
        self.scene.updateMapStatus()
        self.scene.drawStatusLabels()

        if not self.hasDeterminedSurface:
            self.hasDeterminedSurface = True

        for layer in self.layers:
            for row in layer:
                for tile in row:
                    self.renderSurface.blit(tile.image, tile.rect)
        if self.isInside:
            for mob in self.mobManager.mobs:
                self.renderSurface.blit(mob.image, mob.rect)
            
        self.renderSurface.blit(self.player.image, self.player.rect)
        return self.renderSurface